#!/usr/bin python
# -*- coding: utf-8 -*-

from tabulky import UdalostiAutomatu, SmsProOdeslani
import time, traceback
from podpurneFunkce import vytvorSoubor, vymazSoubor
from nacteniKonfigurace import semaforNapeti230V_OK, semaforDvereAutomatuOtevreny

class VyhodnoceniZmenyStavu(object):
    """
    vyhodnocuje neprerusenou dobu trvani daneho stavu (napriklad spinace)
    a podle hystereze prepne do daneho stavu
    odstranuje se tak problem napriklad s kmitanim spinace dveri, 
    nebo s prerusovanou (kmitajici) dodavkou napajeciho napeti 230V
    hysterezi zadavame v sekundach
    """
    def __init__(self, 
                 nazevStavu, 
                 popisyZmenyStavu, 
                 objektNacteniStavu, 
                 hysterezePrechodPodHranicniHodnotu, # cas v sekundach
                 hysterezePrechodNadHranicniHodnotu, # cas v sekundach                                                   
                 hranicniHodnotaPrechoduStavu=None,                  
                 tiskni=False, 
                 priZmeneStavuZaslatSMS = False,
                 signalizacniSoubor = None
                 ):        
        
        vymazSoubor(signalizacniSoubor) # kdyz by nahodou existoval z minula
        self.signalizacniSoubor = signalizacniSoubor
        self.nazevStavu = nazevStavu        
        self.popisyZmenyStavu = popisyZmenyStavu
        self.objektNacteniStavu = objektNacteniStavu                
        self.hysterezePrechodPodHranicniHodnotu = hysterezePrechodPodHranicniHodnotu
        self.hysterezePrechodNadHranicniHodnotu = hysterezePrechodNadHranicniHodnotu
        self.tiskni = tiskni
        self.hranicniHodnotaPrechoduStavu = hranicniHodnotaPrechoduStavu        
        self.priZmeneStavuZaslatSMS = priZmeneStavuZaslatSMS    
        self.aktualniStavJeNadHranicniHodnotou = True
        self.stavJeNadHranicniHodnotouPoprve = True
        self.aktualniStavJePodHranicniHodnotou = True
        self.stavJePodHranicniHodnotouPoprve = True        
        self.frontaVstupnichHodnot = []
     
    def vyhodnotStav(self):
        self.nactiAktualniVstupniHodnotu()
        self.vyhodnotZdaNastalaZmenaStavu()
        self.vyhodnotZdaZmenaStavuTrvaDostatecneDlouho()
        
    def nactiAktualniVstupniHodnotu(self):        
        aktualniStav = self.objektNacteniStavu()        
        self.frontaVstupnichHodnot.append(aktualniStav)
        if len(self.frontaVstupnichHodnot) > 2:
            del self.frontaVstupnichHodnot[0]            
        elif len(self.frontaVstupnichHodnot) == 1:
            # po startu programu
            self.nastavVychoziStav(aktualniStav)
#        print "%s: fronta %s" % (self.nazevStavu, self.frontaVstupnichHodnot)
        
    def nastavVychoziStav(self, aktualniStav):
        self.frontaVstupnichHodnot.append(aktualniStav)
        if aktualniStav <= self.hranicniHodnotaPrechoduStavu:
            print "%s vychozi stav %s" % (self.nazevStavu,  self.popisyZmenyStavu[0])
            self.aktualniStav = self.popisyZmenyStavu[0]
#            print "vychozi stav je POD hranicni hodnotou"
            self.aktualniStavJePodHranicniHodnotou = True
            self.stavPodHranicniHodnotou = False
            self.aktualniStavJeNadHranicniHodnotou = False
            self.stavNadHranicniHodnotou = True            
            self.tStampPrechoduPodHranicniHodnotu = time.time()
        if aktualniStav > self.hranicniHodnotaPrechoduStavu:
            print "%s vychozi stav %s" % (self.nazevStavu,  self.popisyZmenyStavu[1])
            self.aktualniStav = self.popisyZmenyStavu[1]
#            print "vychozi stav je NAD hranicni hodnotou"
            self.aktualniStavJeNadHranicniHodnotou = True
            self.stavNadHranicniHodnotou = False
            self.aktualniStavJePodHranicniHodnotou = False                
            self.stavPodHranicniHodnotou = True
            self.tStampPrechoduNadHranicniHodnotu = time.time()           


    def vyhodnotZdaNastalaZmenaStavu(self):        
        predchoziStav, aktualniStav = self.frontaVstupnichHodnot
        if predchoziStav > self.hranicniHodnotaPrechoduStavu > aktualniStav:            
            # prechod pod hranicni hodnotu       
            print "%s detekovana zmena %s" % (self.nazevStavu,  self.popisyZmenyStavu[0])
            self.aktualniStavJePodHranicniHodnotou = True
            self.aktualniStavJeNadHranicniHodnotou = False
            self.tStampPrechoduPodHranicniHodnotu = time.time()
        elif predchoziStav < self.hranicniHodnotaPrechoduStavu < aktualniStav:            
            # prechod nad hranicni hodnotu            
            print "prechod nad hranicni hodnotu %s: %s" % (self.nazevStavu,  self.popisyZmenyStavu[1])
            self.aktualniStavJeNadHranicniHodnotou = True
            self.aktualniStavJePodHranicniHodnotou = False   
            self.tStampPrechoduNadHranicniHodnotu = time.time()
    
    def vyhodnotZdaZmenaStavuTrvaDostatecneDlouho(self):
        if self.aktualniStavJePodHranicniHodnotou:
            if not self.stavPodHranicniHodnotou:
                if time.time() > self.tStampPrechoduPodHranicniHodnotu + self.hysterezePrechodPodHranicniHodnotu: 
                    textStavu = "%s presel do stavu %s" % (self.nazevStavu,  self.popisyZmenyStavu[0])
                    print textStavu
                    UdalostiAutomatu(popisUdalosti=self.popisyZmenyStavu[0], periferie = self.nazevStavu)
                    self.stavNadHranicniHodnotou = False
                    self.stavPodHranicniHodnotou = True
                    self.aktualniStav = self.popisyZmenyStavu[0]
                    if self.signalizacniSoubor:
                        print "mazu soubor %s" % self.signalizacniSoubor
                        vymazSoubor(self.signalizacniSoubor)
        elif self.aktualniStavJeNadHranicniHodnotou:
            if not self.stavNadHranicniHodnotou:
                if time.time() > self.tStampPrechoduNadHranicniHodnotu + self.hysterezePrechodNadHranicniHodnotu:                            
                    textStavu = "%s presel do stavu %s" % (self.nazevStavu,  self.popisyZmenyStavu[1])
                    print textStavu
                    UdalostiAutomatu(popisUdalosti=self.popisyZmenyStavu[1], periferie = self.nazevStavu)
                    self.stavNadHranicniHodnotou = True
                    self.stavPodHranicniHodnotou = False
                    self.aktualniStav = self.popisyZmenyStavu[1]
                    if self.signalizacniSoubor:
                        print "vytvarim soubor %s" % self.signalizacniSoubor
                        vytvorSoubor(self.signalizacniSoubor)
            
        

if __name__ == "__main__":
    from gpioWinbond import WinbondInputOutput
    
    spinace = WinbondInputOutput()
    
    dvere = VyhodnoceniZmenyStavu(nazevStavu = "DVERE",
                                  # prvni text v popisu zmeny stavu odpovida stavu pod hranicni hodnotou
                                  # druhy text v popisu zmeny stavu odpovida stavu nad hranicni hodnotou
                                  popisyZmenyStavu = ("zavreny", "otevreny"),  
                                  objektNacteniStavu = spinace.dvereOtevreny, 
                                  hysterezePrechodPodHranicniHodnotu = 3, 
                                  hysterezePrechodNadHranicniHodnotu = 3,
                                  hranicniHodnotaPrechoduStavu = 0.5,  # nacitame digitalni hodnoty 0 a 1
                                  tiskni=True, 
                                  signalizacniSoubor = semaforDvereAutomatuOtevreny
                                  )
                                  
    napeti230 = VyhodnoceniZmenyStavu(nazevStavu="230V", 
                                      popisyZmenyStavu = ("odpojeno", "pripojeno"),  
                                      objektNacteniStavu = spinace.napajeciNapetiPripojeno,
                                      hysterezePrechodPodHranicniHodnotu = 3, 
                                      hysterezePrechodNadHranicniHodnotu = 3,                                        
                                      hranicniHodnotaPrechoduStavu = 0.5,  # nacitame digitalni hodnoty 0 a 1
                                      tiskni=True, 
                                      priZmeneStavuZaslatSMS = True,
                                      signalizacniSoubor = semaforNapeti230V_OK                                    
                                      )
                                      
    while 1:
        try:
            spinace.nactiAutomatGpio() # takto nacitame Winbond pouze jednou, setrime procesorovy cas
            dvere.vyhodnotStav()
            napeti230.vyhodnotStav()
            time.sleep(1)
        except:
            traceback.print_exc()
            raise
        
